if(ITK_USE_GPU)
  find_package(OpenCL REQUIRED)
  if(NOT ${OPENCL_FOUND})
    message(
      FATAL
      "Could not find OpenCL"
    )
  endif()

  macro(sourcefile_to_string SOURCE_FILE RESULT_CMAKE_VAR)
    file(STRINGS ${SOURCE_FILE} FileStrings)
    foreach(SourceLine ${FileStrings})
      # replace all \ with \\ to make the c string constant work
      string(REGEX REPLACE "\\\\" "\\\\\\\\" TempSourceLine "${SourceLine}")
      # replace all " with \" to make the c string constant work
      string(REGEX REPLACE "\"" "\\\\\"" EscapedSourceLine "${TempSourceLine}")
      set(
        ${RESULT_CMAKE_VAR}
        "${${RESULT_CMAKE_VAR}}\n\"${EscapedSourceLine}\\n\""
      )
    endforeach()
  endmacro()

  macro(
    write_gpu_kernel_to_file
    OPENCL_FILE
    GPUFILTER_NAME
    GPUFILTER_KERNELNAME
    OUTPUT_FILE
    SRC_VAR
  )
    sourcefile_to_string(${OPENCL_FILE} ${GPUFILTER_KERNELNAME}_SourceString)
    set(
      ${GPUFILTER_KERNELNAME}_KernelString
      "#include \"itk${GPUFILTER_NAME}.h\"\n\n"
    )
    set(
      ${GPUFILTER_KERNELNAME}_KernelString
      "${${GPUFILTER_KERNELNAME}_KernelString}namespace itk\n"
    )
    set(
      ${GPUFILTER_KERNELNAME}_KernelString
      "${${GPUFILTER_KERNELNAME}_KernelString}{\n\n"
    )
    set(
      ${GPUFILTER_KERNELNAME}_KernelString
      "${${GPUFILTER_KERNELNAME}_KernelString}const char* ${GPUFILTER_KERNELNAME}::GetOpenCLSource()\n"
    )
    set(
      ${GPUFILTER_KERNELNAME}_KernelString
      "${${GPUFILTER_KERNELNAME}_KernelString}{\n"
    )
    set(
      ${GPUFILTER_KERNELNAME}_KernelString
      "${${GPUFILTER_KERNELNAME}_KernelString}  return ${${GPUFILTER_KERNELNAME}_SourceString};\n"
    )
    set(
      ${GPUFILTER_KERNELNAME}_KernelString
      "${${GPUFILTER_KERNELNAME}_KernelString}}\n\n"
    )
    set(
      ${GPUFILTER_KERNELNAME}_KernelString
      "${${GPUFILTER_KERNELNAME}_KernelString}}\n"
    )

    file(
      WRITE
      ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}
      "${${GPUFILTER_KERNELNAME}_KernelString}"
    )

    configure_file(
      ${OPENCL_FILE}
      ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}.cl
      COPYONLY
    )
    add_custom_target(
      ${GPUFILTER_KERNELNAME}_Target
      DEPENDS
        ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}
        ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt
        ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}.cl
    )
    set_source_files_properties(
      ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}
      PROPERTIES
        GENERATED
          ON
    )
    set(
      ${SRC_VAR}
      ${${SRC_VAR}}
      ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}
    )
  endmacro()

  macro(write_gpu_kernels GPUKernels GPU_SRC)
    foreach(GPUKernel ${GPUKernels})
      get_filename_component(FilterName ${GPUKernel} NAME_WE)
      write_gpu_kernel_to_file(
              ${GPUKernel}
              ${FilterName}
              ${FilterName}Kernel
              "${FilterName}Kernel.cxx"
              ${GPU_SRC}
      )
    endforeach()
  endmacro()
endif()
